Analysis
Imports & Libraries
# install.packages("tidyverse")
library(tidyverse)
# install.packages("rvest")
library(rvest)
# install.packages("janitor")
library(janitor)
# install.packages("plotly")
library(plotly)
Webpage Links
# Primary Data Source from 2020-2023
prime <- "https://www.basketball-reference.com/teams/MIL/2023/gamelog/"
prime2 <- "https://www.basketball-reference.com/teams/MIL/2022/gamelog/"
prime3 <- "https://www.basketball-reference.com/teams/MIL/2021/gamelog/"
# Secondary Data Source from 2020-2023
sec <- "https://www.teamrankings.com/nba/rankings/teams/?date=2023-04-22"
sec2 <- "https://www.teamrankings.com/nba/rankings/teams/?date=2022-06-17"
sec3 <- "https://www.teamrankings.com/nba/rankings/teams/?date=2021-07-21"
Function to Read Tables
# Leverage Web Scarping to Create Data tables
readTables <- function(list) {
tables <- c()
for (i in list) {
temp <- i %>%
read_html() %>%
html_nodes(css = "table") %>%
html_table(fill = TRUE)
tables <- c(tables, temp)
}
return(tables)
}
Save Tables
# Read Tables
data <- readTables(list(prime, prime2, prime3, sec, sec2, sec3))
# Save Game Data for each Year
game_data1 <- data[[1]]
game_data2 <- data[[2]]
game_data3 <- data[[3]]
# Save Rank Data for each Year
rank_data1 <- data[[4]]
rank_data2 <- data[[5]]
rank_data3 <- data[[6]]
Technical Challenge: Because our tables are web
scarped, each contain multiple syntax and format errors (unnecessary and
repetitive columns and rows). As such, wrangling the tables into a
unified syntax will be vital. Unfortunately, many inconsistencies make
cleaning them all with a single function unrealistic.
Game Data Wrangling and Cleaning
# Game data for year 2022-2023
game_data1 <- game_data1[-5,] # drop first 5 rows
game_data1 <- game_data1[,-c(4,1)] # drop columns 1 and 4
game_data1 <- game_data1 %>% row_to_names(row_number = 1) # reset cols
game_data1 <- game_data1[-c(20,21,42,43,64,65,86,87),] # drop redundant rows
game_data1 <- game_data1[,-c(21,22,23,24,25,26,27,28,29,30)] # opponent stats
game_data1 <- game_data1[,-c(21,22,23,24,25,26,27)] # redundant columns
colnames(game_data1)[6] = "opp points"
colnames(game_data1)[4] = "Outcome"
game_data1$Date <- as.POSIXct(game_data1$Date, format="%Y")
game_data1$Year <- year(game_data1$Date) # create new year column
# Game data for year 2021-2022
game_data2 <- game_data2[-5,]
game_data2 <- game_data2[,-c(4,1)]
game_data2 <- game_data2 %>% row_to_names(row_number = 1)
game_data2 <- game_data2[-c(20,21,42,43,64,65,86,87),]
game_data2 <- game_data2[,-c(21,22,23,24,25,26,27,28,29,30)]
game_data2 <- game_data2[,-c(21,22,23,24,25,26,27)]
colnames(game_data2)[6] = "opp points"
colnames(game_data2)[4] = "Outcome"
game_data2$Date <- as.POSIXct(game_data2$Date, format="%Y")
game_data2$Year <- year(game_data2$Date)
# Game data for year 2020-2021
game_data3 <- game_data3[,-c(4,1)]
game_data3 <- game_data3 %>% row_to_names(row_number = 1)
colnames(game_data3)[6] = "opp points"
colnames(game_data3)[4] = "Outcome"
game_data3 <- game_data3[,-c(21,22,23,24,25,26,27,28,29,30)]
game_data3 <- game_data3[-c(20,21,43,44,65,66),]
game_data3 <- game_data3[,-c(21,22,23,24,25,26,27)]
game_data3$Date <- as.POSIXct(game_data3$Date, format="%Y-%m-%d")
game_data3$Year <- year(game_data3$Date)
Rank Data Wrangling and Cleaning
rank_data1 <- rank_data1[,-c(3,4,5,6,7)]
colnames(rank_data1)[2] = "Rank"
rank_data1 <- rank_data1 %>%
mutate(ABV = c("BOS", "CLE","PHI", "MIL","DEN","MEM","NYK","PHO","GSW","TOR","SAC","NOP","BRK","CHI","LAC", "LAL","ATL","MIA","DAL","MIN","OKC","WAS","UTA","ORL","POR","IND","CHO","DET","HOU","SAS"))
rank_data2 <- rank_data2[,-c(3,4,5,6,7)]
colnames(rank_data2)[2] = "Rank"
rank_data2 <- rank_data2 %>%
mutate(ABV = c("BOS","PHO","GSW","UTA","MEM","MIA", "MIL","DAL","PHI","DEN","MIN","BRK","TOR","ATL","CLE","CHO","LAC", "NYK", "NOP","CHI","SAS","LAL","IND","WAS","SAC","POR","DET","OKC","ORL","HOU"))
rank_data3 <- rank_data3[,-c(3,4,5,6,7)]
colnames(rank_data3)[2] = "Rank"
rank_data3 <- rank_data3 %>%
mutate(ABV = c("UTA","LAC","MIL","PHO","PHI","BRK","DEN","LAL","DAL","ATL","POR","BOS","GSW","MEM","NYK","MIA","IND","TOR","NOP","CHI","SAS","WAS","CHO","SAC","DET","MIN","HOU","ORL","CLE","OKC"))
Our game and rank tables are now fully processed. Joining them using
the left_join function will ensure that each case has the correct
information from both datasets. Furthermore, combining the joined tables
with the rbind function will produce a final table with a nearly
300-game sample size to investigate.
Combining Game Data and Rank Data
# Join Game and Ranks
game_data1 <- game_data1 %>%
left_join(rank_data1, by = c("Opp"="ABV"))
game_data2 <- game_data2 %>%
left_join(rank_data2, by = c("Opp"="ABV"))
game_data3 <- game_data3 %>%
left_join(rank_data3, by = c("Opp"="ABV"))
game_data3 <- game_data3[-20,]
# Final Game Data Table
games <- rbind(game_data3, game_data2, game_data1)
games <- games[-20,]
# Convert Chr to Numeric
games[, c("G", "Tm","opp points","FG","FGA","FG%","3P","3PA","3P%","FT","FTA","FT%","ORB","TRB","AST","STL","BLK","TOV","PF","Rank")] <- lapply(games[, c("G", "Tm","opp points","FG","FGA","FG%","3P","3PA","3P%","FT","FTA","FT%","ORB","TRB","AST","STL","BLK","TOV","PF","Rank")], as.numeric)
# Inspecting Final Table
head(games)
# summary(games)
With the help of fundamental functions like head and summary, we can
see that the final “games” table is formatted correctly and ready for
further analysis.
The three major categories explored in this project surround the
most impactful elements of a game: Offense, Defense, and Shooting. We
investigated each of these areas below.
Effect of Assist-Turnover Ratio on Outcomes (Offense)
game1 <- games %>%
group_by(Outcome, Year, Rank) %>%
summarise(TeamRank = paste(Team, "Rank -", Rank, sep = " "), AST = AST, TOV = TOV, AT = AST/TOV)
game_1 <- game1 %>%
mutate(Outcome = ifelse(Outcome == "W", 1,0))
# Null Hypothesis: The value of the Assist-Turnover ratio has minimal impact game outcome
Off_corr <- cor(game_1$AT,game_1$Outcome, method = "pearson")
Off_model <- wilcox.test(game1$AT ~ game1$Outcome, conf.int =T)
# Mean of Assist-Turnover ratio for Wins
off_wins <- game1 %>%
select(Outcome, Year,Rank, AT) %>%
filter(Outcome == "W")
offW_mean <- mean(off_wins$AT)
# Mean of Assist-Turnover ratio for Losses
off_losses <- game1 %>%
select(Outcome, Year, Rank, AT) %>%
filter(Outcome == "L")
offL_mean <- mean(off_losses$AT)
print(Off_corr)
print(Off_model)
print(offW_mean)
print(offL_mean)
Let’s define the variables we focused on above: An Assist is a pass
made to a teammate which leads directly to a score. A Turnover is when a
player commits an error and allows the opposing team to gain possession
of the ball.
Utilizing the Mann-Whitney U test, we explore the Assist-Turnover
ratio’s impact on the game outcome above. The test shows a significant
difference in means between games won and lost (P-Value : 0.0016). If we
further interpret the calculated means, we see that more assists, in
turn a higher ratio, significantly impact winning.
Supporting Visualization
game1_filtered <- filter(game1, Year != 2020)
p <- ggplot(game1_filtered, aes(x = AST, y = TOV, color = Outcome, text = TeamRank)) +
geom_point() +
labs(x = "Assists", y = "Turnovers", color = "Game Outcome") +
theme_minimal() +
facet_wrap(. ~ Year) +
ggtitle("Assists vs. Turnovers by Game Outcome and Year") +
theme(panel.spacing.x = unit(5, "mm"))
ggplotly(p, tooltip = c("text"), width = 900, height = 300)
The spread of the points indicates that there is little correlation.
This result is consistent with the correlation we found earlier (0.144).
However, despite a lack of correlation, we can observe that most games
with a high Assist-Turnover ratio are wins. As such, The Buck’s coaching
staff should emphasize smart and controlled ball movement to minimize
turnovers and maximize assists.
Effect of Defensive Possessions on Outcomes (Defense)
game2 <- games %>%
group_by(Outcome, Year, Rank) %>%
summarise(TeamRank = paste(Team, "Rank -", Rank, sep = " "), PF = PF, DRB = TRB - ORB, DES = (DRB + BLK + STL - PF), Def_ratio = PF/ DES)
game_2 <- game2 %>%
mutate(Outcome = ifelse(Outcome == "W", 1,0))
# Null Hypothesis: The value of the Defensive ratio has minimal impact game outcome
def_corr <- cor(game_2$Def_ratio,game_2$Outcome, method = "pearson")
def_model <- wilcox.test(game2$Def_ratio ~ game2$Outcome, conf.int =T)
# Mean of Defensive ratio for Wins
def_wins <- game2 %>%
select(Outcome, Year, Rank, Def_ratio) %>%
filter(Outcome == "W")
defW_mean <- mean(def_wins$Def_ratio)
# Mean of Defensive ratio for Losses
def_losses <- game2 %>%
select(Outcome, Year, Rank, Def_ratio) %>%
filter(Outcome == "L")
defL_mean <- mean(def_losses$Def_ratio)
print(def_corr) # Correlation
print(def_model) # U Test
print(defW_mean) # Mean of Defensive ratio for Wins
print(defL_mean) # Mean of Defensive ratio for Losses
Let’s define the variables we focused on here: A Personal Foul (PF)
is any illegal contact with an offensive player, including pushing and
striking. The Defensive Efficiency Score (DES) is the difference between
good and bad defensive actions.
Now we explored Defensive Possession’s impact on the game outcome
above. The Mann-Whitney U tests show a significant difference in means
between games won and lost (P-Value : 0.0003). If we further interpret
the calculated means, we see that fewer personal fouls significantly
impact winning.
Supporting Visualization
game2_filtered <- filter(game2, Year != 2020)
p2 <- ggplot(game2_filtered, aes(x = DES, y = PF , color = Outcome, text =TeamRank)) +
geom_point() +
labs(x = "Defensive Efficiency Score", y = "Personal Fouls Commited", color = "Game Outcome") +
theme_minimal() +
facet_wrap(. ~ Year) +
ggtitle("Efficiency of Defensive Possessions") +
theme(panel.spacing.x = unit(5, "mm"))
ggplotly(p2, tooltip = c("text"), width = 900, height = 300)
NA
In the graphs above, we can see a moderate negative correlation
between our variables. This result is consistent with the correlation we
found earlier (-0.277). This relationship suggests that personal fouls
decrease as DES increases. Combining correlation and difference of means
we can advise the Buck’s coaching staff to emphasize strategic
positioning and team defense to win the most games.
Effect of Thee Point Field Goal Attempts on Outcomes (Shooting)
game3 <- games %>%
group_by(Outcome, Year, Rank) %>%
summarise(TeamRank = paste(Team, "Rank -", Rank, sep = " "), `3PA` = `3PA`, `3P%` = `3P%`, Percent_attempt = (`3P%`/`3PA`))
game_3 <- game3 %>%
mutate(Outcome = ifelse(Outcome == "W", 1,0))
# Null Hypothesis: The value of the Percent-Attempt ratio has minimal impact game outcome
shot_corr <- cor(game_3$Percent_attempt,game_3$`3PA`, method = "pearson")
shot_model <- wilcox.test(game3$Percent_attempt ~ game3$Outcome, conf.int =T)
# Mean of Percent-Attempt ratio for Wins
shot_wins <- game3 %>%
select(Outcome, Year, Rank, Percent_attempt) %>%
filter(Outcome == "W")
shotW_mean <- mean(shot_wins$Percent_attempt)
# Mean of Percent-Attempt ratio for Losses
shot_losses <- game3 %>%
select(Outcome, Year, Rank, Percent_attempt) %>%
filter(Outcome == "L")
shotL_mean <- mean(shot_losses$Percent_attempt)
print(shot_corr) # Correlation
print(shot_model) # U Test
print(shotW_mean) # Mean of Percent-Attempt ratio for Wins
print(shotL_mean) # Mean of Percent-Attempt ratio for Losses
Let’s define the variables we focused on above: A three-point
attempt is a shot released from any position behind the three-point arc.
The percent-attempt ratio takes both shooting accuracy and the volume
into account to measure shooting efficency.
Here, we explored the percent-attempt ratio’s impact on the game
outcome above. The Mann-Whitney U tests, once again, show a significant
difference in means between games won and lost (P-Value : 0.0003). If we
further interpret the calculated means, we see that fewer personal fouls
significantly impact winning.
Supporting Visualization
game3_filtered <- filter(game3, Year != 2020)
p3 <- ggplot(game3_filtered, aes(x = Percent_attempt, y = `3PA` , color = Outcome, text =TeamRank)) +
geom_point()+
labs(x = "Shooting Accuracy Score", y = "3 Point Field Goal Attempts", color = "Game Outcome") +
theme_minimal() +
facet_wrap(. ~ Year) +
ggtitle("Impact of 3 Point Field Goal Attempts") +
theme(panel.spacing.x = unit(5, "mm"))
ggplotly(p3, tooltip = c("text"), width = 900, height = 300)
Finally, we can see the strongest negative correlation between our
variables (-0.592). This relationship suggests that as three-point
attempts decrease, the percent-attempt ratio increases. Combining
correlation and the U test we can advise Buck’s coaching staff to
strategize and create open shoots instead of frequent ones.
LS0tDQp0aXRsZTogIk1pbHdhdWtlZSBCdWNrcyBBbmFseXNpcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoqKioqKg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCiMjIyBfX0JhY2tncm91bmRfXw0KDQojIyMgSW4gdGhpcyBwcm9qZWN0LCBJIGFuYWx5emUgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBNaWx3YXVrZWUgQnVja3MsIGEgcHJvbWluZW50IE5hdGlvbmFsIEJhc2tldGJhbGwgQXNzb2NpYXRpb24gKE5CQSkgdGVhbS4gV2UgaW52ZXN0aWdhdGUgdGhlIHJlZ3VsYXIgc2Vhc29uIGRhdGEgYW5kIGlkZW50aWZ5IHRoZSB0ZWFtIHBlcmZvcm1hbmNlIGluZGljYXRvcnMgbW9zdCBzaWduaWZpY2FudCB0byB3aW5uaW5nLiANCioqKioqDQoNCiMjIyBfX1NvdXJjZSBEYXRhX18NCg0KIyMjIyBbUHJpbWFyeSBEYXRhXShodHRwczovL3d3dy5iYXNrZXRiYWxsLXJlZmVyZW5jZS5jb20vdGVhbXMvTUlMLzIwMjMvZ2FtZWxvZy8pDQoNCiMjIyMgW1NlY29uZGFyeSBEYXRhXShodHRwczovL3d3dy50ZWFtcmFua2luZ3MuY29tL25iYS9yYW5raW5ncy90ZWFtcy8/ZGF0YT0yMDIzLTA0LTIyKQ0KDQojIyMjIFtBZGRpdGlvbmFsIEluZm9ybWF0aW9uXShodHRwczovL2dpdGh1Yi5jb20vTW9oYW1lZC1FbG16L01pbHdhdWtlZS1CdWNrcy1BbmFseXNpcykNCg0KKioqKioNCiMjIyBfX0FuYWx5c2lzX18NCioqKioqDQojIyMjIEltcG9ydHMgJiBMaWJyYXJpZXMNCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMgaW5zdGFsbC5wYWNrYWdlcygicnZlc3QiKQ0KbGlicmFyeShydmVzdCkNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJqYW5pdG9yIikNCmxpYnJhcnkoamFuaXRvcikNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KbGlicmFyeShwbG90bHkpDQpgYGANCiMjIyMgV2VicGFnZSBMaW5rcw0KYGBge3J9DQojIFByaW1hcnkgRGF0YSBTb3VyY2UgZnJvbSAyMDIwLTIwMjMNCnByaW1lIDwtICJodHRwczovL3d3dy5iYXNrZXRiYWxsLXJlZmVyZW5jZS5jb20vdGVhbXMvTUlMLzIwMjMvZ2FtZWxvZy8iDQpwcmltZTIgPC0gImh0dHBzOi8vd3d3LmJhc2tldGJhbGwtcmVmZXJlbmNlLmNvbS90ZWFtcy9NSUwvMjAyMi9nYW1lbG9nLyINCnByaW1lMyA8LSAiaHR0cHM6Ly93d3cuYmFza2V0YmFsbC1yZWZlcmVuY2UuY29tL3RlYW1zL01JTC8yMDIxL2dhbWVsb2cvIg0KDQojIFNlY29uZGFyeSBEYXRhIFNvdXJjZSBmcm9tIDIwMjAtMjAyMw0Kc2VjIDwtICJodHRwczovL3d3dy50ZWFtcmFua2luZ3MuY29tL25iYS9yYW5raW5ncy90ZWFtcy8/ZGF0ZT0yMDIzLTA0LTIyIg0Kc2VjMiA8LSAiaHR0cHM6Ly93d3cudGVhbXJhbmtpbmdzLmNvbS9uYmEvcmFua2luZ3MvdGVhbXMvP2RhdGU9MjAyMi0wNi0xNyINCnNlYzMgPC0gImh0dHBzOi8vd3d3LnRlYW1yYW5raW5ncy5jb20vbmJhL3JhbmtpbmdzL3RlYW1zLz9kYXRlPTIwMjEtMDctMjEiDQpgYGANCiMjIyMgRnVuY3Rpb24gdG8gUmVhZCBUYWJsZXMgDQpgYGB7cn0NCiMgTGV2ZXJhZ2UgV2ViIFNjYXJwaW5nIHRvIENyZWF0ZSBEYXRhIHRhYmxlcw0KcmVhZFRhYmxlcyA8LSBmdW5jdGlvbihsaXN0KSB7DQogIHRhYmxlcyA8LSBjKCkNCiAgZm9yIChpIGluIGxpc3QpIHsNCiAgICAgIHRlbXAgPC0gaSAlPiUNCiAgICAgIHJlYWRfaHRtbCgpICU+JQ0KICAgICAgaHRtbF9ub2Rlcyhjc3MgPSAidGFibGUiKSAlPiUNCiAgICAgIGh0bWxfdGFibGUoZmlsbCA9IFRSVUUpDQogICAgICB0YWJsZXMgPC0gYyh0YWJsZXMsIHRlbXApDQogIH0NCiAgcmV0dXJuKHRhYmxlcykNCn0NCmBgYA0KIyMjIyBTYXZlIFRhYmxlcw0KYGBge3J9DQojIFJlYWQgVGFibGVzIA0KZGF0YSA8LSByZWFkVGFibGVzKGxpc3QocHJpbWUsIHByaW1lMiwgcHJpbWUzLCBzZWMsIHNlYzIsIHNlYzMpKSANCg0KIyBTYXZlIEdhbWUgRGF0YSBmb3IgZWFjaCBZZWFyDQpnYW1lX2RhdGExIDwtIGRhdGFbWzFdXQ0KZ2FtZV9kYXRhMiA8LSBkYXRhW1syXV0NCmdhbWVfZGF0YTMgPC0gZGF0YVtbM11dDQoNCiMgU2F2ZSBSYW5rIERhdGEgZm9yIGVhY2ggWWVhcg0KcmFua19kYXRhMSA8LSBkYXRhW1s0XV0NCnJhbmtfZGF0YTIgPC0gZGF0YVtbNV1dDQpyYW5rX2RhdGEzIDwtIGRhdGFbWzZdXQ0KYGBgDQoqKioqKg0KIyMjIyBfX1RlY2huaWNhbCBDaGFsbGVuZ2U6X18gQmVjYXVzZSBvdXIgdGFibGVzIGFyZSB3ZWIgc2NhcnBlZCwgZWFjaCBjb250YWluIG11bHRpcGxlIHN5bnRheCBhbmQgZm9ybWF0IGVycm9ycyAodW5uZWNlc3NhcnkgYW5kIHJlcGV0aXRpdmUgY29sdW1ucyBhbmQgcm93cykuIEFzIHN1Y2gsIHdyYW5nbGluZyB0aGUgdGFibGVzIGludG8gYSB1bmlmaWVkIHN5bnRheCB3aWxsIGJlIHZpdGFsLiBVbmZvcnR1bmF0ZWx5LCBtYW55IGluY29uc2lzdGVuY2llcyBtYWtlIGNsZWFuaW5nIHRoZW0gYWxsIHdpdGggYSBzaW5nbGUgZnVuY3Rpb24gdW5yZWFsaXN0aWMuIA0KKioqKioNCiMjIyMgR2FtZSBEYXRhIFdyYW5nbGluZyBhbmQgQ2xlYW5pbmcNCmBgYHtyfQ0KIyBHYW1lIGRhdGEgZm9yIHllYXIgMjAyMi0yMDIzDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTFbLTUsXSAjIGRyb3AgZmlyc3QgNSByb3dzDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTFbLC1jKDQsMSldICMgZHJvcCBjb2x1bW5zIDEgYW5kIDQNCmdhbWVfZGF0YTEgPC0gZ2FtZV9kYXRhMSAlPiUgcm93X3RvX25hbWVzKHJvd19udW1iZXIgPSAxKSAjIHJlc2V0IGNvbHMNCmdhbWVfZGF0YTEgPC0gZ2FtZV9kYXRhMVstYygyMCwyMSw0Miw0Myw2NCw2NSw4Niw4NyksXSAjIGRyb3AgcmVkdW5kYW50IHJvd3MNCmdhbWVfZGF0YTEgPC0gZ2FtZV9kYXRhMVssLWMoMjEsMjIsMjMsMjQsMjUsMjYsMjcsMjgsMjksMzApXSAjIG9wcG9uZW50IHN0YXRzDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTFbLC1jKDIxLDIyLDIzLDI0LDI1LDI2LDI3KV0gIyByZWR1bmRhbnQgY29sdW1ucw0KY29sbmFtZXMoZ2FtZV9kYXRhMSlbNl0gPSAib3BwIHBvaW50cyINCmNvbG5hbWVzKGdhbWVfZGF0YTEpWzRdID0gIk91dGNvbWUiDQpnYW1lX2RhdGExJERhdGUgPC0gYXMuUE9TSVhjdChnYW1lX2RhdGExJERhdGUsIGZvcm1hdD0iJVkiKQ0KZ2FtZV9kYXRhMSRZZWFyIDwtIHllYXIoZ2FtZV9kYXRhMSREYXRlKSAjIGNyZWF0ZSBuZXcgeWVhciBjb2x1bW4NCg0KIyBHYW1lIGRhdGEgZm9yIHllYXIgMjAyMS0yMDIyDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLTUsXSANCmdhbWVfZGF0YTIgPC0gZ2FtZV9kYXRhMlssLWMoNCwxKV0gDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTIgJT4lIHJvd190b19uYW1lcyhyb3dfbnVtYmVyID0gMSkgDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLWMoMjAsMjEsNDIsNDMsNjQsNjUsODYsODcpLF0gDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLC1jKDIxLDIyLDIzLDI0LDI1LDI2LDI3LDI4LDI5LDMwKV0gDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLC1jKDIxLDIyLDIzLDI0LDI1LDI2LDI3KV0NCmNvbG5hbWVzKGdhbWVfZGF0YTIpWzZdID0gIm9wcCBwb2ludHMiDQpjb2xuYW1lcyhnYW1lX2RhdGEyKVs0XSA9ICJPdXRjb21lIg0KZ2FtZV9kYXRhMiREYXRlIDwtIGFzLlBPU0lYY3QoZ2FtZV9kYXRhMiREYXRlLCBmb3JtYXQ9IiVZIikNCmdhbWVfZGF0YTIkWWVhciA8LSB5ZWFyKGdhbWVfZGF0YTIkRGF0ZSkgDQoNCiMgR2FtZSBkYXRhIGZvciB5ZWFyIDIwMjAtMjAyMQ0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWywtYyg0LDEpXSANCmdhbWVfZGF0YTMgPC0gZ2FtZV9kYXRhMyAlPiUgcm93X3RvX25hbWVzKHJvd19udW1iZXIgPSAxKSANCmNvbG5hbWVzKGdhbWVfZGF0YTMpWzZdID0gIm9wcCBwb2ludHMiDQpjb2xuYW1lcyhnYW1lX2RhdGEzKVs0XSA9ICJPdXRjb21lIg0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWywtYygyMSwyMiwyMywyNCwyNSwyNiwyNywyOCwyOSwzMCldIA0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWy1jKDIwLDIxLDQzLDQ0LDY1LDY2KSxdIA0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWywtYygyMSwyMiwyMywyNCwyNSwyNiwyNyldIA0KZ2FtZV9kYXRhMyREYXRlIDwtIGFzLlBPU0lYY3QoZ2FtZV9kYXRhMyREYXRlLCBmb3JtYXQ9IiVZLSVtLSVkIikNCmdhbWVfZGF0YTMkWWVhciA8LSB5ZWFyKGdhbWVfZGF0YTMkRGF0ZSkgDQpgYGANCiMjIyMgUmFuayBEYXRhIFdyYW5nbGluZyBhbmQgQ2xlYW5pbmcgDQpgYGB7cn0NCnJhbmtfZGF0YTEgPC0gcmFua19kYXRhMVssLWMoMyw0LDUsNiw3KV0NCmNvbG5hbWVzKHJhbmtfZGF0YTEpWzJdID0gIlJhbmsiDQpyYW5rX2RhdGExIDwtIHJhbmtfZGF0YTEgJT4lDQogIG11dGF0ZShBQlYgPSBjKCJCT1MiLCAiQ0xFIiwiUEhJIiwgIk1JTCIsIkRFTiIsIk1FTSIsIk5ZSyIsIlBITyIsIkdTVyIsIlRPUiIsIlNBQyIsIk5PUCIsIkJSSyIsIkNISSIsIkxBQyIsICJMQUwiLCJBVEwiLCJNSUEiLCJEQUwiLCJNSU4iLCJPS0MiLCJXQVMiLCJVVEEiLCJPUkwiLCJQT1IiLCJJTkQiLCJDSE8iLCJERVQiLCJIT1UiLCJTQVMiKSkNCg0KcmFua19kYXRhMiA8LSByYW5rX2RhdGEyWywtYygzLDQsNSw2LDcpXQ0KY29sbmFtZXMocmFua19kYXRhMilbMl0gPSAiUmFuayINCnJhbmtfZGF0YTIgPC0gcmFua19kYXRhMiAlPiUNCiAgbXV0YXRlKEFCViA9IGMoIkJPUyIsIlBITyIsIkdTVyIsIlVUQSIsIk1FTSIsIk1JQSIsICJNSUwiLCJEQUwiLCJQSEkiLCJERU4iLCJNSU4iLCJCUksiLCJUT1IiLCJBVEwiLCJDTEUiLCJDSE8iLCJMQUMiLCAiTllLIiwgIk5PUCIsIkNISSIsIlNBUyIsIkxBTCIsIklORCIsIldBUyIsIlNBQyIsIlBPUiIsIkRFVCIsIk9LQyIsIk9STCIsIkhPVSIpKQ0KDQpyYW5rX2RhdGEzIDwtIHJhbmtfZGF0YTNbLC1jKDMsNCw1LDYsNyldDQpjb2xuYW1lcyhyYW5rX2RhdGEzKVsyXSA9ICJSYW5rIg0KcmFua19kYXRhMyA8LSByYW5rX2RhdGEzICU+JQ0KICBtdXRhdGUoQUJWID0gYygiVVRBIiwiTEFDIiwiTUlMIiwiUEhPIiwiUEhJIiwiQlJLIiwiREVOIiwiTEFMIiwiREFMIiwiQVRMIiwiUE9SIiwiQk9TIiwiR1NXIiwiTUVNIiwiTllLIiwiTUlBIiwiSU5EIiwiVE9SIiwiTk9QIiwiQ0hJIiwiU0FTIiwiV0FTIiwiQ0hPIiwiU0FDIiwiREVUIiwiTUlOIiwiSE9VIiwiT1JMIiwiQ0xFIiwiT0tDIikpDQpgYGANCioqKioqDQojIyMjIE91ciBnYW1lIGFuZCByYW5rIHRhYmxlcyBhcmUgbm93IGZ1bGx5IHByb2Nlc3NlZC4gSm9pbmluZyB0aGVtIHVzaW5nIHRoZSBsZWZ0X2pvaW4gZnVuY3Rpb24gd2lsbCBlbnN1cmUgdGhhdCBlYWNoIGNhc2UgaGFzIHRoZSBjb3JyZWN0IGluZm9ybWF0aW9uIGZyb20gYm90aCBkYXRhc2V0cy4gRnVydGhlcm1vcmUsIGNvbWJpbmluZyB0aGUgam9pbmVkIHRhYmxlcyB3aXRoIHRoZSByYmluZCBmdW5jdGlvbiB3aWxsIHByb2R1Y2UgYSBmaW5hbCB0YWJsZSB3aXRoIGEgbmVhcmx5IDMwMC1nYW1lIHNhbXBsZSBzaXplIHRvIGludmVzdGlnYXRlLg0KDQoqKioqKg0KDQojIyMjIENvbWJpbmluZyBHYW1lIERhdGEgYW5kIFJhbmsgRGF0YQ0KYGBge3J9DQojIEpvaW4gR2FtZSBhbmQgUmFua3MgDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTEgJT4lDQogIGxlZnRfam9pbihyYW5rX2RhdGExLCBieSA9IGMoIk9wcCI9IkFCViIpKQ0KZ2FtZV9kYXRhMiA8LSBnYW1lX2RhdGEyICU+JQ0KICBsZWZ0X2pvaW4ocmFua19kYXRhMiwgYnkgPSBjKCJPcHAiPSJBQlYiKSkNCmdhbWVfZGF0YTMgPC0gZ2FtZV9kYXRhMyAlPiUNCiAgbGVmdF9qb2luKHJhbmtfZGF0YTMsIGJ5ID0gYygiT3BwIj0iQUJWIikpDQoNCmdhbWVfZGF0YTMgPC0gZ2FtZV9kYXRhM1stMjAsXSANCg0KIyBGaW5hbCBHYW1lIERhdGEgVGFibGUgDQpnYW1lcyA8LSByYmluZChnYW1lX2RhdGEzLCBnYW1lX2RhdGEyLCBnYW1lX2RhdGExKQ0KZ2FtZXMgPC0gZ2FtZXNbLTIwLF0NCg0KIyBDb252ZXJ0IENociB0byBOdW1lcmljIA0KZ2FtZXNbLCBjKCJHIiwgIlRtIiwib3BwIHBvaW50cyIsIkZHIiwiRkdBIiwiRkclIiwiM1AiLCIzUEEiLCIzUCUiLCJGVCIsIkZUQSIsIkZUJSIsIk9SQiIsIlRSQiIsIkFTVCIsIlNUTCIsIkJMSyIsIlRPViIsIlBGIiwiUmFuayIpXSA8LSBsYXBwbHkoZ2FtZXNbLCBjKCJHIiwgIlRtIiwib3BwIHBvaW50cyIsIkZHIiwiRkdBIiwiRkclIiwiM1AiLCIzUEEiLCIzUCUiLCJGVCIsIkZUQSIsIkZUJSIsIk9SQiIsIlRSQiIsIkFTVCIsIlNUTCIsIkJMSyIsIlRPViIsIlBGIiwiUmFuayIpXSwgYXMubnVtZXJpYykNCg0KIyBJbnNwZWN0aW5nIEZpbmFsIFRhYmxlIA0KaGVhZChnYW1lcykNCiMgc3VtbWFyeShnYW1lcykNCmBgYA0KKioqKioNCiMjIyMgV2l0aCB0aGUgaGVscCBvZiBmdW5kYW1lbnRhbCBmdW5jdGlvbnMgbGlrZSBoZWFkIGFuZCBzdW1tYXJ5LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGZpbmFsICJnYW1lcyIgdGFibGUgaXMgZm9ybWF0dGVkIGNvcnJlY3RseSBhbmQgcmVhZHkgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuDQoNCiMjIyMgVGhlIHRocmVlIG1ham9yIGNhdGVnb3JpZXMgZXhwbG9yZWQgaW4gdGhpcyBwcm9qZWN0IHN1cnJvdW5kIHRoZSBtb3N0IGltcGFjdGZ1bCBlbGVtZW50cyBvZiBhIGdhbWU6IE9mZmVuc2UsIERlZmVuc2UsIGFuZCBTaG9vdGluZy4gV2UgaW52ZXN0aWdhdGVkIGVhY2ggb2YgdGhlc2UgYXJlYXMgYmVsb3cuDQoqKioqKg0KDQojIyMjIEVmZmVjdCBvZiBBc3Npc3QtVHVybm92ZXIgUmF0aW8gb24gT3V0Y29tZXMgKE9mZmVuc2UpDQpgYGB7cn0NCmdhbWUxIDwtIGdhbWVzICU+JQ0KICBncm91cF9ieShPdXRjb21lLCBZZWFyLCBSYW5rKSAlPiUNCiAgc3VtbWFyaXNlKFRlYW1SYW5rID0gcGFzdGUoVGVhbSwgIlJhbmsgLSIsIFJhbmssIHNlcCA9ICIgIiksIEFTVCA9IEFTVCwgVE9WID0gVE9WLCBBVCA9IEFTVC9UT1YpDQoNCmdhbWVfMSA8LSBnYW1lMSAlPiUNCiAgbXV0YXRlKE91dGNvbWUgPSBpZmVsc2UoT3V0Y29tZSA9PSAiVyIsIDEsMCkpDQoNCiMgTnVsbCBIeXBvdGhlc2lzOiBUaGUgdmFsdWUgb2YgdGhlIEFzc2lzdC1UdXJub3ZlciByYXRpbyBoYXMgbWluaW1hbCBpbXBhY3QgZ2FtZSBvdXRjb21lDQoNCk9mZl9jb3JyIDwtIGNvcihnYW1lXzEkQVQsZ2FtZV8xJE91dGNvbWUsIG1ldGhvZCA9ICJwZWFyc29uIikgIA0KT2ZmX21vZGVsIDwtIHdpbGNveC50ZXN0KGdhbWUxJEFUIH4gZ2FtZTEkT3V0Y29tZSwgY29uZi5pbnQgPVQpDQoNCiMgTWVhbiBvZiBBc3Npc3QtVHVybm92ZXIgcmF0aW8gZm9yIFdpbnMNCm9mZl93aW5zIDwtIGdhbWUxICU+JQ0KICBzZWxlY3QoT3V0Y29tZSwgWWVhcixSYW5rLCBBVCkgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJXIikNCm9mZldfbWVhbiA8LSBtZWFuKG9mZl93aW5zJEFUKSANCiAgDQojIE1lYW4gb2YgQXNzaXN0LVR1cm5vdmVyIHJhdGlvIGZvciBMb3NzZXMNCm9mZl9sb3NzZXMgPC0gZ2FtZTEgJT4lDQogIHNlbGVjdChPdXRjb21lLCBZZWFyLCBSYW5rLCBBVCkgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJMIikNCm9mZkxfbWVhbiA8LSBtZWFuKG9mZl9sb3NzZXMkQVQpDQoNCnByaW50KE9mZl9jb3JyKQ0KcHJpbnQoT2ZmX21vZGVsKQ0KcHJpbnQob2ZmV19tZWFuKQ0KcHJpbnQob2ZmTF9tZWFuKQ0KYGBgDQoqKioqKg0KIyMjIyBMZXQncyBkZWZpbmUgdGhlIHZhcmlhYmxlcyB3ZSBmb2N1c2VkIG9uIGFib3ZlOiBBbiBBc3Npc3QgaXMgYSBwYXNzIG1hZGUgdG8gYSB0ZWFtbWF0ZSB3aGljaCBsZWFkcyBkaXJlY3RseSB0byBhIHNjb3JlLiBBIFR1cm5vdmVyIGlzIHdoZW4gYSBwbGF5ZXIgY29tbWl0cyBhbiBlcnJvciBhbmQgYWxsb3dzIHRoZSBvcHBvc2luZyB0ZWFtIHRvIGdhaW4gcG9zc2Vzc2lvbiBvZiB0aGUgYmFsbC4gDQoNCiMjIyMgVXRpbGl6aW5nIHRoZSBNYW5uLVdoaXRuZXkgVSB0ZXN0LCB3ZSBleHBsb3JlIHRoZSBBc3Npc3QtVHVybm92ZXIgcmF0aW8ncyBpbXBhY3Qgb24gdGhlIGdhbWUgb3V0Y29tZSBhYm92ZS4gVGhlIHRlc3Qgc2hvd3MgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIG1lYW5zIGJldHdlZW4gZ2FtZXMgd29uIGFuZCBsb3N0IChQLVZhbHVlIDogMC4wMDE2KS4gSWYgd2UgZnVydGhlciBpbnRlcnByZXQgdGhlIGNhbGN1bGF0ZWQgbWVhbnMsIHdlIHNlZSB0aGF0IG1vcmUgYXNzaXN0cywgaW4gdHVybiBhIGhpZ2hlciByYXRpbywgc2lnbmlmaWNhbnRseSBpbXBhY3Qgd2lubmluZy4NCg0KKioqKioNCiMjIyMgU3VwcG9ydGluZyBWaXN1YWxpemF0aW9uDQpgYGB7cn0NCmdhbWUxX2ZpbHRlcmVkIDwtIGZpbHRlcihnYW1lMSwgWWVhciAhPSAyMDIwKQ0KDQpwIDwtIGdncGxvdChnYW1lMV9maWx0ZXJlZCwgYWVzKHggPSBBU1QsIHkgPSBUT1YsIGNvbG9yID0gT3V0Y29tZSwgdGV4dCA9IFRlYW1SYW5rKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHggPSAiQXNzaXN0cyIsIHkgPSAiVHVybm92ZXJzIiwgY29sb3IgPSAiR2FtZSBPdXRjb21lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBmYWNldF93cmFwKC4gfiBZZWFyKSArDQogIGdndGl0bGUoIkFzc2lzdHMgdnMuIFR1cm5vdmVycyBieSBHYW1lIE91dGNvbWUgYW5kIFllYXIiKSArDQogIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoNSwgIm1tIikpDQoNCmdncGxvdGx5KHAsIHRvb2x0aXAgPSBjKCJ0ZXh0IiksIHdpZHRoID0gOTAwLCBoZWlnaHQgPSAzMDApDQpgYGANCg0KKioqKioNCiMjIyMgVGhlIHNwcmVhZCBvZiB0aGUgcG9pbnRzIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIGxpdHRsZSBjb3JyZWxhdGlvbi4gVGhpcyByZXN1bHQgaXMgY29uc2lzdGVudCB3aXRoIHRoZSBjb3JyZWxhdGlvbiB3ZSBmb3VuZCBlYXJsaWVyICgwLjE0NCkuIEhvd2V2ZXIsIGRlc3BpdGUgYSBsYWNrIG9mIGNvcnJlbGF0aW9uLCB3ZSBjYW4gb2JzZXJ2ZSB0aGF0IG1vc3QgZ2FtZXMgd2l0aCBhIGhpZ2ggQXNzaXN0LVR1cm5vdmVyIHJhdGlvIGFyZSB3aW5zLiBBcyBzdWNoLCBUaGUgQnVjaydzIGNvYWNoaW5nIHN0YWZmIHNob3VsZCBlbXBoYXNpemUgc21hcnQgYW5kIGNvbnRyb2xsZWQgYmFsbCBtb3ZlbWVudCB0byBtaW5pbWl6ZSB0dXJub3ZlcnMgYW5kIG1heGltaXplIGFzc2lzdHMuDQoNCioqKioqDQojIyMjIEVmZmVjdCBvZiBEZWZlbnNpdmUgUG9zc2Vzc2lvbnMgb24gT3V0Y29tZXMgKERlZmVuc2UpDQpgYGB7cn0NCmdhbWUyIDwtIGdhbWVzICU+JQ0KICBncm91cF9ieShPdXRjb21lLCBZZWFyLCBSYW5rKSAlPiUNCiAgc3VtbWFyaXNlKFRlYW1SYW5rID0gcGFzdGUoVGVhbSwgIlJhbmsgLSIsIFJhbmssIHNlcCA9ICIgIiksIFBGID0gUEYsICBEUkIgPSBUUkIgLSBPUkIsIERFUyA9IChEUkIgKyBCTEsgKyBTVEwgLSBQRiksIERlZl9yYXRpbyA9IFBGLyBERVMpDQoNCmdhbWVfMiA8LSBnYW1lMiAlPiUNCiAgbXV0YXRlKE91dGNvbWUgPSBpZmVsc2UoT3V0Y29tZSA9PSAiVyIsIDEsMCkpDQoNCiMgTnVsbCBIeXBvdGhlc2lzOiBUaGUgdmFsdWUgb2YgdGhlIERlZmVuc2l2ZSByYXRpbyBoYXMgbWluaW1hbCBpbXBhY3QgZ2FtZSBvdXRjb21lDQoNCmRlZl9jb3JyIDwtIGNvcihnYW1lXzIkRGVmX3JhdGlvLGdhbWVfMiRPdXRjb21lLCBtZXRob2QgPSAicGVhcnNvbiIpICANCmRlZl9tb2RlbCA8LSB3aWxjb3gudGVzdChnYW1lMiREZWZfcmF0aW8gfiBnYW1lMiRPdXRjb21lLCBjb25mLmludCA9VCkNCg0KIyBNZWFuIG9mIERlZmVuc2l2ZSByYXRpbyBmb3IgV2lucw0KZGVmX3dpbnMgPC0gZ2FtZTIgJT4lDQogIHNlbGVjdChPdXRjb21lLCBZZWFyLCBSYW5rLCBEZWZfcmF0aW8pICU+JQ0KICBmaWx0ZXIoT3V0Y29tZSA9PSAiVyIpDQpkZWZXX21lYW4gPC0gbWVhbihkZWZfd2lucyREZWZfcmF0aW8pIA0KICANCiMgTWVhbiBvZiBEZWZlbnNpdmUgcmF0aW8gZm9yIExvc3Nlcw0KZGVmX2xvc3NlcyA8LSBnYW1lMiAlPiUNCiAgc2VsZWN0KE91dGNvbWUsIFllYXIsIFJhbmssIERlZl9yYXRpbykgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJMIikNCmRlZkxfbWVhbiA8LSBtZWFuKGRlZl9sb3NzZXMkRGVmX3JhdGlvKQ0KDQpwcmludChkZWZfY29ycikgIyBDb3JyZWxhdGlvbg0KcHJpbnQoZGVmX21vZGVsKSAjIFUgVGVzdA0KcHJpbnQoZGVmV19tZWFuKSAjIE1lYW4gb2YgRGVmZW5zaXZlIHJhdGlvIGZvciBXaW5zDQpwcmludChkZWZMX21lYW4pICMgTWVhbiBvZiBEZWZlbnNpdmUgcmF0aW8gZm9yIExvc3Nlcw0KDQpgYGANCioqKioqDQojIyMjIExldCdzIGRlZmluZSB0aGUgdmFyaWFibGVzIHdlIGZvY3VzZWQgb24gaGVyZTogQSBQZXJzb25hbCBGb3VsIChQRikgaXMgYW55IGlsbGVnYWwgY29udGFjdCB3aXRoIGFuIG9mZmVuc2l2ZSBwbGF5ZXIsIGluY2x1ZGluZyBwdXNoaW5nIGFuZCBzdHJpa2luZy4gVGhlIERlZmVuc2l2ZSBFZmZpY2llbmN5IFNjb3JlIChERVMpIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gZ29vZCBhbmQgYmFkIGRlZmVuc2l2ZSBhY3Rpb25zLg0KDQojIyMjIE5vdyB3ZSBleHBsb3JlZCBEZWZlbnNpdmUgUG9zc2Vzc2lvbidzIGltcGFjdCBvbiB0aGUgZ2FtZSBvdXRjb21lIGFib3ZlLiBUaGUgTWFubi1XaGl0bmV5IFUgdGVzdHMgc2hvdyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gbWVhbnMgYmV0d2VlbiBnYW1lcyB3b24gYW5kIGxvc3QgKFAtVmFsdWUgOiAwLjAwMDMpLiBJZiB3ZSBmdXJ0aGVyIGludGVycHJldCB0aGUgY2FsY3VsYXRlZCBtZWFucywgd2Ugc2VlIHRoYXQgZmV3ZXIgcGVyc29uYWwgZm91bHMgc2lnbmlmaWNhbnRseSBpbXBhY3Qgd2lubmluZy4NCioqKioqDQoNCiMjIyMgU3VwcG9ydGluZyBWaXN1YWxpemF0aW9uDQpgYGB7cn0NCmdhbWUyX2ZpbHRlcmVkIDwtIGZpbHRlcihnYW1lMiwgWWVhciAhPSAyMDIwKQ0KDQpwMiA8LSBnZ3Bsb3QoZ2FtZTJfZmlsdGVyZWQsIGFlcyh4ID0gREVTLCB5ID0gUEYgLCBjb2xvciA9IE91dGNvbWUsIHRleHQgPVRlYW1SYW5rKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHggPSAiRGVmZW5zaXZlIEVmZmljaWVuY3kgU2NvcmUiLCB5ID0gIlBlcnNvbmFsIEZvdWxzIENvbW1pdGVkIiwgY29sb3IgPSAiR2FtZSBPdXRjb21lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBmYWNldF93cmFwKC4gfiBZZWFyKSArDQogIGdndGl0bGUoIkVmZmljaWVuY3kgb2YgRGVmZW5zaXZlIFBvc3Nlc3Npb25zIikgKw0KICB0aGVtZShwYW5lbC5zcGFjaW5nLnggPSB1bml0KDUsICJtbSIpKQ0KDQpnZ3Bsb3RseShwMiwgdG9vbHRpcCA9IGMoInRleHQiKSwgd2lkdGggPSA5MDAsIGhlaWdodCA9IDMwMCkNCg0KYGBgDQoqKioqKg0KDQojIyMjIEluIHRoZSBncmFwaHMgYWJvdmUsIHdlIGNhbiBzZWUgYSBtb2RlcmF0ZSBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG91ciB2YXJpYWJsZXMuIFRoaXMgcmVzdWx0IGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgY29ycmVsYXRpb24gd2UgZm91bmQgZWFybGllciAoLTAuMjc3KS4gVGhpcyByZWxhdGlvbnNoaXAgc3VnZ2VzdHMgdGhhdCBwZXJzb25hbCBmb3VscyBkZWNyZWFzZSBhcyBERVMgaW5jcmVhc2VzLiBDb21iaW5pbmcgY29ycmVsYXRpb24gYW5kIGRpZmZlcmVuY2Ugb2YgbWVhbnMgd2UgY2FuIGFkdmlzZSB0aGUgQnVjaydzIGNvYWNoaW5nIHN0YWZmIHRvIGVtcGhhc2l6ZSBzdHJhdGVnaWMgcG9zaXRpb25pbmcgYW5kIHRlYW0gZGVmZW5zZSB0byB3aW4gdGhlIG1vc3QgZ2FtZXMuDQoNCioqKioqDQojIyMjIEVmZmVjdCBvZiBUaGVlIFBvaW50IEZpZWxkIEdvYWwgQXR0ZW1wdHMgb24gT3V0Y29tZXMgKFNob290aW5nKQ0KYGBge3J9DQpnYW1lMyA8LSBnYW1lcyAlPiUNCiAgZ3JvdXBfYnkoT3V0Y29tZSwgWWVhciwgUmFuaykgJT4lDQogIHN1bW1hcmlzZShUZWFtUmFuayA9IHBhc3RlKFRlYW0sICJSYW5rIC0iLCBSYW5rLCBzZXAgPSAiICIpLCBgM1BBYCA9IGAzUEFgLCBgM1AlYCA9IGAzUCVgLCBQZXJjZW50X2F0dGVtcHQgPSAoYDNQJWAvYDNQQWApKQ0KDQpnYW1lXzMgPC0gZ2FtZTMgJT4lDQogIG11dGF0ZShPdXRjb21lID0gaWZlbHNlKE91dGNvbWUgPT0gIlciLCAxLDApKQ0KDQojIE51bGwgSHlwb3RoZXNpczogVGhlIHZhbHVlIG9mIHRoZSBQZXJjZW50LUF0dGVtcHQgcmF0aW8gaGFzIG1pbmltYWwgaW1wYWN0IGdhbWUgb3V0Y29tZQ0KDQpzaG90X2NvcnIgPC0gY29yKGdhbWVfMyRQZXJjZW50X2F0dGVtcHQsZ2FtZV8zJGAzUEFgLCBtZXRob2QgPSAicGVhcnNvbiIpICANCnNob3RfbW9kZWwgPC0gd2lsY294LnRlc3QoZ2FtZTMkUGVyY2VudF9hdHRlbXB0IH4gZ2FtZTMkT3V0Y29tZSwgY29uZi5pbnQgPVQpDQoNCiMgTWVhbiBvZiBQZXJjZW50LUF0dGVtcHQgcmF0aW8gZm9yIFdpbnMNCnNob3Rfd2lucyA8LSBnYW1lMyAlPiUNCiAgc2VsZWN0KE91dGNvbWUsIFllYXIsIFJhbmssIFBlcmNlbnRfYXR0ZW1wdCkgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJXIikNCnNob3RXX21lYW4gPC0gbWVhbihzaG90X3dpbnMkUGVyY2VudF9hdHRlbXB0KSANCiAgDQojIE1lYW4gb2YgUGVyY2VudC1BdHRlbXB0IHJhdGlvIGZvciBMb3NzZXMNCnNob3RfbG9zc2VzIDwtIGdhbWUzICU+JQ0KICBzZWxlY3QoT3V0Y29tZSwgWWVhciwgUmFuaywgUGVyY2VudF9hdHRlbXB0KSAlPiUNCiAgZmlsdGVyKE91dGNvbWUgPT0gIkwiKQ0Kc2hvdExfbWVhbiA8LSBtZWFuKHNob3RfbG9zc2VzJFBlcmNlbnRfYXR0ZW1wdCkNCg0KcHJpbnQoc2hvdF9jb3JyKSAjIENvcnJlbGF0aW9uDQpwcmludChzaG90X21vZGVsKSAjIFUgVGVzdA0KcHJpbnQoc2hvdFdfbWVhbikgIyBNZWFuIG9mIFBlcmNlbnQtQXR0ZW1wdCByYXRpbyBmb3IgV2lucw0KcHJpbnQoc2hvdExfbWVhbikgIyBNZWFuIG9mIFBlcmNlbnQtQXR0ZW1wdCByYXRpbyBmb3IgTG9zc2VzDQpgYGANCioqKioqDQoNCiMjIyMgTGV0J3MgZGVmaW5lIHRoZSB2YXJpYWJsZXMgd2UgZm9jdXNlZCBvbiBhYm92ZTogQSB0aHJlZS1wb2ludCBhdHRlbXB0IGlzIGEgc2hvdCByZWxlYXNlZCBmcm9tIGFueSBwb3NpdGlvbiBiZWhpbmQgdGhlIHRocmVlLXBvaW50IGFyYy4gVGhlIHBlcmNlbnQtYXR0ZW1wdCByYXRpbyB0YWtlcyBib3RoIHNob290aW5nIGFjY3VyYWN5IGFuZCB0aGUgdm9sdW1lIGludG8gYWNjb3VudCB0byBtZWFzdXJlIHNob290aW5nIGVmZmljZW5jeS4NCg0KIyMjIyBIZXJlLCB3ZSBleHBsb3JlZCB0aGUgcGVyY2VudC1hdHRlbXB0IHJhdGlvJ3MgaW1wYWN0IG9uIHRoZSBnYW1lIG91dGNvbWUgYWJvdmUuIFRoZSBNYW5uLVdoaXRuZXkgVSB0ZXN0cywgb25jZSBhZ2Fpbiwgc2hvdyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gbWVhbnMgYmV0d2VlbiBnYW1lcyB3b24gYW5kIGxvc3QgKFAtVmFsdWUgOiAwLjAwMDMpLiBJZiB3ZSBmdXJ0aGVyIGludGVycHJldCB0aGUgY2FsY3VsYXRlZCBtZWFucywgd2Ugc2VlIHRoYXQgZmV3ZXIgcGVyc29uYWwgZm91bHMgc2lnbmlmaWNhbnRseSBpbXBhY3Qgd2lubmluZy4NCg0KKioqKioNCiMjIyMgU3VwcG9ydGluZyBWaXN1YWxpemF0aW9uDQpgYGB7cn0NCmdhbWUzX2ZpbHRlcmVkIDwtIGZpbHRlcihnYW1lMywgWWVhciAhPSAyMDIwKQ0KDQpwMyA8LSBnZ3Bsb3QoZ2FtZTNfZmlsdGVyZWQsIGFlcyh4ID0gUGVyY2VudF9hdHRlbXB0LCB5ID0gYDNQQWAgLCBjb2xvciA9IE91dGNvbWUsIHRleHQgPVRlYW1SYW5rKSkgKw0KICBnZW9tX3BvaW50KCkrDQogIGxhYnMoeCA9ICJTaG9vdGluZyBBY2N1cmFjeSBTY29yZSIsIHkgPSAiMyBQb2ludCBGaWVsZCBHb2FsIEF0dGVtcHRzIiwgY29sb3IgPSAiR2FtZSBPdXRjb21lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBmYWNldF93cmFwKC4gfiBZZWFyKSArDQogIGdndGl0bGUoIkltcGFjdCBvZiAzIFBvaW50IEZpZWxkIEdvYWwgQXR0ZW1wdHMiKSArDQogIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoNSwgIm1tIikpDQoNCmdncGxvdGx5KHAzLCB0b29sdGlwID0gYygidGV4dCIpLCB3aWR0aCA9IDkwMCwgaGVpZ2h0ID0gMzAwKQ0KYGBgDQoqKioqKg0KIyMjIyBGaW5hbGx5LCB3ZSBjYW4gc2VlIHRoZSBzdHJvbmdlc3QgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBvdXIgdmFyaWFibGVzICgtMC41OTIpLiBUaGlzIHJlbGF0aW9uc2hpcCBzdWdnZXN0cyB0aGF0IGFzIHRocmVlLXBvaW50IGF0dGVtcHRzIGRlY3JlYXNlLCB0aGUgcGVyY2VudC1hdHRlbXB0IHJhdGlvIGluY3JlYXNlcy4gQ29tYmluaW5nIGNvcnJlbGF0aW9uIGFuZCB0aGUgVSB0ZXN0IHdlIGNhbiBhZHZpc2UgQnVjaydzIGNvYWNoaW5nIHN0YWZmIHRvIHN0cmF0ZWdpemUgYW5kIGNyZWF0ZSBvcGVuIHNob290cyBpbnN0ZWFkIG9mIGZyZXF1ZW50IG9uZXMuDQoNCioqKioqDQojIyMgQ29uY2x1c2lvbg0KDQojIyMjIEFmdGVyIGV4YW1pbmluZyB0aGUgdGhyZWUgbW9zdCBpbXBhY3RmdWwgZWxlbWVudHMgKE9mZmVuc2UsIERlZmVuc2UsIGFuZCBTaG9vdGluZyksIHdlIHByb3ZpZGVkIHRoZSBNaWx3YXVrZWUgQnVja3MgY29hY2hpbmcgc3RhZmYgd2l0aCBtZWFuaW5nZnVsIGluc2lnaHRzIGJhY2tlZCBieSByZWxpYWJsZSBzdGF0aXN0aWNhbCB0ZXN0cy4gTm93LCBpdCBpcyB1cCB0byB0aGVpciBvcmdhbml6YXRpb24gdG8gaW1wbGVtZW50IHRoZW0gYXBwcm9wcmlhdGVseSBhcyB0aGV5IGVudGVyIHRoZSBwbGF5b2Zmcy4NCg0KKioqKio=